﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using  PI_CS_Library.PicsNetwork_Information_Model;
using  PI_CS_Library.Virtual_Network_Information_Model;
using TransportLayer.Manager;

namespace  PI_CS_Library
{
    public class SubnetworkConnectionController
    {
        Engine _managerEngine;
        PicsNetwork _network;

        public SubnetworkConnectionController(PicsNetwork _currNetwork, Engine _currEngine)
        {
            _network = _currNetwork;
            _managerEngine = _currEngine;
        }

        // picsNC przyjmuje zleccenie w jakiejś formie, następnie korzystając PicsNetwork->VirtualNetwork odnajduje wskazane łącza i umieszcza je w liście
        public PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection SetUpNetworkConnection(int _newConnectionId, int _virtualNetworkId, Dictionary<int, Dictionary<int, PicsLink>> _linkList, NwTTP _srcPoint, NwTTP _sinkPoint, int _capacity)
        {
            TransportLayer.Manager.NetworkConnection _managerNetworkConnection;

            if (_newConnectionId == -1) _managerNetworkConnection = new TransportLayer.Manager.NetworkConnection(_managerEngine.GetFreeId());
            else _managerNetworkConnection = new TransportLayer.Manager.NetworkConnection(_newConnectionId);

            PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection _newNetworkConnection
                 = new PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection(_srcPoint, _sinkPoint, _managerNetworkConnection.Id, _capacity);

            TransportLayer.Manager.LinkConnection _userSourceLinkConnection = GetUserLinkConnection(_srcPoint);
            _managerNetworkConnection.Path.Add(_userSourceLinkConnection);

            //_linkList.ElementAt(0).Key;

            int _firstPicsLinkId = _linkList.ElementAt(0).Value.ElementAt(0).Key;
            int _firstVirtualLinkId = _linkList.ElementAt(0).Key;

            int _firstCtpPort = _managerEngine.Links[_firstPicsLinkId].SourcePort;

            CTP _previousCTP = new CTP(_firstCtpPort, Direction.SourceSink);

            MatrixConnection<NwTTP, CTP> _firstMatrixConnection = new MatrixConnection<NwTTP, CTP>(_srcPoint, _previousCTP, _newNetworkConnection.Id);

            _newNetworkConnection.AddMatrixConnection<NwTTP, CTP>(_firstMatrixConnection);

            _network.GetVirtualNetwork(_virtualNetworkId).LinkList[_firstVirtualLinkId].SrcMatrix.AddMatrixConnection<NwTTP, CTP>(_firstMatrixConnection);

            for (int i = 0; i < _linkList.Count; i++)
            {
                int _currVirtualLinkId = _linkList.ElementAt(i).Key;
                Dictionary<int, PicsLink> _currPicsLinkList = _linkList.ElementAt(i).Value;

                Link _currVirtualLink = _network.GetVirtualNetwork(_virtualNetworkId).LinkList[_currVirtualLinkId];

                int _lastPicsLinkId = _currPicsLinkList.Last().Key;

                int _currCtpPort = _managerEngine.Links[_lastPicsLinkId].TargetPort;

                CTP _nextCTP = new CTP(_currCtpPort, Direction.SourceSink);

                for (int k = 0; k < _currPicsLinkList.Count; k++)
                {
                    PicsLink _currPicsLink = _currPicsLinkList.ElementAt(k).Value;

                    int _currSrcPort = _managerEngine.Links[_currPicsLink.Id.Number].SourcePort;
                    int _currDstPort = _managerEngine.Links[_currPicsLink.Id.Number].TargetPort;

                    TransportLayer.Manager.LinkConnection _managerLinkConnection = new TransportLayer.Manager.LinkConnection();

                    _managerLinkConnection.SourceId = _currPicsLink.SrcMatrix.Id.Number;
                    _managerLinkConnection.TargetId = _currPicsLink.SinkMatrix.Id.Number;

                    _managerLinkConnection.SourceRouting = Convert.ToString(_currSrcPort);
                    _managerLinkConnection.TargetRouting = Convert.ToString(_currDstPort);

                    _managerNetworkConnection.Path.Add(_managerLinkConnection);

                }

                Virtual_Network_Information_Model.LinkConnection _newLinkConnection = new Virtual_Network_Information_Model.LinkConnection(_previousCTP, _nextCTP, _currVirtualLink.Id, _newNetworkConnection.Id);

                _newNetworkConnection.LinkConnectionsList.Add(_newLinkConnection.Id.Number, _newLinkConnection);
                _currVirtualLink.LinkConnectionsList.Add(_newLinkConnection.Id.Number, _newLinkConnection);


                Matrix _nextNode = _currVirtualLink.SinkMatrix;

                _previousCTP = _nextCTP;

                if (i == _linkList.Count - 1)
                {
                    MatrixConnection<CTP, NwTTP> _lastMatrixConnection = new MatrixConnection<CTP, NwTTP>(_previousCTP, _sinkPoint, _newNetworkConnection.Id);

                    _nextNode.AddMatrixConnection<CTP, NwTTP>(_lastMatrixConnection);

                    _newNetworkConnection.AddMatrixConnection<CTP, NwTTP>(_lastMatrixConnection);

                    TransportLayer.Manager.LinkConnection _userSinkLinkConnection = GetUserLinkConnection(_sinkPoint);
                    _managerNetworkConnection.Path.Add(_userSinkLinkConnection);

                }

                else
                {
                    int _nextVirtualLinkId = _linkList.ElementAt(i + 1).Key;

                    Link _nextVirtualLink = _network.GetVirtualNetwork(_virtualNetworkId).LinkList[_nextVirtualLinkId];

                    _firstPicsLinkId = _linkList.ElementAt(i).Value.First().Key;

                    int _nextCtpPort = _managerEngine.Links[_firstPicsLinkId].SourcePort;

                    _nextCTP = new CTP(_nextCtpPort, Direction.SourceSink);

                    MatrixConnection<CTP, CTP> _newMatrixConnection = new MatrixConnection<CTP, CTP>(_previousCTP, _nextCTP, _newNetworkConnection.Id);

                    _nextNode.AddMatrixConnection<CTP, CTP>(_newMatrixConnection);

                    _newNetworkConnection.AddMatrixConnection<CTP, CTP>(_newMatrixConnection);

                    _previousCTP = _nextCTP;
                }
            }

            _managerEngine.AddUserConnection(_managerNetworkConnection);
            _managerEngine.SetupUserConnection(_managerNetworkConnection.Id);

            _network.GetVirtualNetwork(_virtualNetworkId).AddNetworkConnection(_newNetworkConnection);

            return _newNetworkConnection;       
        }

        public void TearDownNetworkConnection(int _vnId, int _connId)
        {
            PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection _oldConnection =
                _network.GetVirtualNetwork(_vnId).GetNetworkConnection(_connId);

            int _matrixId;
            int _matrixConnectionId;

            for (int i = 1; i < _oldConnection.MatrixConnectionsList.Count-1; i++)
            {
                _matrixId = (_oldConnection.MatrixConnectionsList.ElementAt(i).Value as MatrixConnection<CTP, CTP>).MatrixId.Number;
                _matrixConnectionId = _oldConnection.MatrixConnectionsList.ElementAt(i).Key;
                _network.GetVirtualNetwork(_vnId).GetMatrix(_matrixId).RemoveMatrixConnection(_matrixConnectionId);
            }

            _matrixId = (_oldConnection.MatrixConnectionsList.First().Value as MatrixConnection<NwTTP, CTP>).MatrixId.Number;
            _matrixConnectionId = _oldConnection.MatrixConnectionsList.First().Key;
            _network.GetVirtualNetwork(_vnId).GetMatrix(_matrixId).RemoveMatrixConnection(_matrixConnectionId);
            _matrixId = (_oldConnection.MatrixConnectionsList.Last().Value as MatrixConnection<CTP, NwTTP>).MatrixId.Number;
            _matrixConnectionId = _oldConnection.MatrixConnectionsList.Last().Key;
            _network.GetVirtualNetwork(_vnId).GetMatrix(_matrixId).RemoveMatrixConnection(_matrixConnectionId);

            foreach (PI_CS_Library.Virtual_Network_Information_Model.LinkConnection lc in _oldConnection.LinkConnectionsList.Values)
            {
                int _linkId = lc.LinkId.Number;
                _network.GetVirtualNetwork(_vnId).GetLink(_linkId).LinkConnectionsList.Remove(lc.Id.Number);
                _network.GetVirtualNetwork(_vnId).GetLink(_linkId).Parameters.AvailableCapacity += _oldConnection.Capacity;
            }

            _network.GetVirtualNetwork(_vnId).DeleteNetworkConnection(_connId);

            _managerEngine.Disconnect(_connId);
        }
        /*
        public int SetUpNetworkConnection(int _virtualNetworkId, Dictionary<int, PicsLink> _connLinkList, NwTTP _srcPoint, NwTTP _sinkPoint) 
        {
             PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection _newNetworkConnection
                = new  PI_CS_Library.Virtual_Network_Information_Model.NetworkConnection(_srcPoint, _sinkPoint);

            TransportLayer.Manager.NetworkConnection _managerNetworkConnection = new TransportLayer.Manager.NetworkConnection(_managerEngine.GetFreeId());

            TransportLayer.Manager.LinkConnection _userSourceLinkConnection = GetUserLinkConnection(_srcPoint);
            _managerNetworkConnection.Path.Add(_userSourceLinkConnection);

            int _firstLinkId = _connLinkList.Values.First().Id.Number;

            int _firstCtpPort = _managerEngine.Links[_firstLinkId].SourcePort;

            CTP _previousCTP = new CTP(_firstCtpPort, Direction.SourceSink);

            MatrixConnection<NwTTP, CTP> _firstMatrixConnection = new MatrixConnection<NwTTP, CTP>(_srcPoint, _previousCTP, _newNetworkConnection.Id);

            _newNetworkConnection.AddMatrixConnection<NwTTP, CTP>(_firstMatrixConnection);

            _connLinkList.Values.First().SrcMatrix.AddMatrixConnection<NwTTP, CTP>(_firstMatrixConnection);

            for (int i = 0; i < _connLinkList.Values.Count; i++)
            {
                Link _currLink = _connLinkList.Values.ElementAt(i);

                int _currLinkId = _currLink.Id.Number;

                int _currCtpPort = _managerEngine.Links[_currLinkId].TargetPort;

                CTP _nextCTP = new CTP(_currCtpPort, Direction.SourceSink);

                Virtual_Network_Information_Model.LinkConnection _newLinkConnection = new Virtual_Network_Information_Model.LinkConnection(_previousCTP, _nextCTP, _currLink.Id, _newNetworkConnection.Id);

                _currLink.LinkConnectionsList.Add(_newLinkConnection.Id.Number, _newLinkConnection);
                _newNetworkConnection.LinkConnectionsList.Add(_newLinkConnection.Id.Number, _newLinkConnection);

                TransportLayer.Manager.LinkConnection _managerLinkConnection = new TransportLayer.Manager.LinkConnection();

                _managerLinkConnection.SourceId = _currLink.SrcMatrix.Id.Number;
                _managerLinkConnection.TargetId = _currLink.SinkMatrix.Id.Number;

                _managerLinkConnection.SourceRouting = Convert.ToString(_newLinkConnection.SrcPoint.PortNr);
                _managerLinkConnection.TargetRouting = Convert.ToString(_newLinkConnection.SinkPoint.PortNr);

                _managerNetworkConnection.Path.Add(_managerLinkConnection);

                Matrix _nextNode = _currLink.SinkMatrix;

                _previousCTP = _nextCTP;

                if (i == _connLinkList.Values.Count - 1)
                {
                    MatrixConnection<CTP, NwTTP> _lastMatrixConnection = new MatrixConnection<CTP, NwTTP>(_previousCTP, _sinkPoint, _newNetworkConnection.Id);

                    _nextNode.AddMatrixConnection<CTP, NwTTP>(_lastMatrixConnection);

                    _newNetworkConnection.AddMatrixConnection<CTP, NwTTP>(_lastMatrixConnection);

                    TransportLayer.Manager.LinkConnection _userSinkLinkConnection = GetUserLinkConnection(_sinkPoint);
                    _managerNetworkConnection.Path.Add(_userSinkLinkConnection);
                
                }

                else
                {
                    int _nextLinkId = _connLinkList.Values.ElementAt(i+1).Id.Number;

                    int _nextCtpPort = _managerEngine.Links[_nextLinkId].SourcePort;

                    _nextCTP = new CTP(_nextCtpPort, Direction.SourceSink);

                    MatrixConnection<CTP, CTP> _newMatrixConnection = new MatrixConnection<CTP, CTP>(_previousCTP, _nextCTP, _newNetworkConnection.Id);

                    _nextNode.AddMatrixConnection<CTP, CTP>(_newMatrixConnection);

                    _newNetworkConnection.AddMatrixConnection<CTP, CTP>(_newMatrixConnection);

                    _previousCTP = _nextCTP;
                }
            }
            _managerEngine.AddConnection(_managerNetworkConnection);
            _managerEngine.Connect(_managerNetworkConnection.Id);

            _network.GetVirtualNetwork(_virtualNetworkId).AddNetworkConnection(_newNetworkConnection);

            return _newNetworkConnection.Id.Number;
        }

        */
        public TransportLayer.Manager.LinkConnection GetUserLinkConnection(NwTTP _ttp)
        {
            TransportLayer.Manager.LinkConnection _userLinkConnection = new TransportLayer.Manager.LinkConnection();

            TransportLayer.Manager.Engine.Link _userLink = _managerEngine.Links[_ttp.UserLinkId];

            _userLinkConnection.SourceId = _userLink.SourceNode.Id;
            _userLinkConnection.TargetId = _userLink.TargetNode.Id;

            _userLinkConnection.SourceRouting = Convert.ToString(_userLink.SourcePort);
            _userLinkConnection.TargetRouting = Convert.ToString(_userLink.TargetPort);

            return _userLinkConnection;

        }
    }
}
